/********************************************************************
 *                                                                  *
 * THIS FILE IS PART OF THE OggVorbis 'TREMOR' CODEC SOURCE CODE.   *
 *                                                                  *
 * USE, DISTRIBUTION AND REPRODUCTION OF THIS LIBRARY SOURCE IS     *
 * GOVERNED BY A BSD-STYLE SOURCE LICENSE INCLUDED WITH THIS SOURCE *
 * IN 'COPYING'. PLEASE READ THESE TERMS BEFORE DISTRIBUTING.       *
 *                                                                  *
 * THE OggVorbis 'TREMOR' SOURCE CODE IS (C) COPYRIGHT 1994-2002    *
 * BY THE Xiph.Org FOUNDATION http://www.xiph.org/                  *
 *                                                                  *
 ********************************************************************

 function: simple example decoder using vorbisidec

 ********************************************************************/

/* Takes a vorbis bitstream from stdin and writes raw stereo PCM to
   stdout using vorbisfile. Using vorbisfile is much simpler than
   dealing with libvorbis. */
#include <types.h>
#include <sys_config.h>
#include <retcode.h>

#include <api/libc/alloc.h>
#include <api/libc/string.h>
#include <api/libc/printf.h>
#include <api/libfs2/unistd.h>
#include <api/libfs2/stdio.h>

#include "ivorbiscodec.h"
#include "ivorbisfile.h"


static char pcmout[1024 * 16]; /* take 4k out of the data segment, not the stack */

#if 0

#define DAC_PRECISION	24
#define PCM_FRM_NUM 			400

UINT32 snd_samplerate = 48000;

struct deca_device*	g_deca_dev  = NULL;
struct snd_device*		g_snd_dev = NULL;
INT32 pcm_left_ch[1152];
INT32 pcm_right_ch[1152];

static void libc_demo_pcm_output(struct pcm_output * pcm)
{
	UINT8 pcm_frm_header[16];
	UINT32 temp;
	static UINT32 avoid_under_run = 0;

	//config pcm frame header
	MEMSET(pcm_frm_header, 0, 16);
	if (pcm->samp_num&0x00000003)
	{
		//PRINTF("err sample num = %d \n",pcm->samp_num);
		return;
	}
	temp = pcm->samp_num;
	if (DAC_PRECISION == 16)
		temp = temp >> 1 ;

	pcm_frm_header[12] = ((UINT8*)(&temp))[0];
	pcm_frm_header[13] = ((UINT8*)(&temp))[1];

	if (SND_STATE_PLAY != g_snd_dev->flags && 0 == avoid_under_run)
	{

		if (RET_SUCCESS != snd_config(g_snd_dev, snd_samplerate, pcm->samp_num, DAC_PRECISION))
			return;

		snd_write_pcm_data(g_snd_dev, pcm, (UINT32*)pcm_frm_header);
		avoid_under_run = 5;
		return;
	}

	if (0 != avoid_under_run)
	{
		snd_write_pcm_data(g_snd_dev, pcm, (UINT32*)pcm_frm_header);
		avoid_under_run--;
		if (0 == avoid_under_run)
			snd_start(g_snd_dev);
		return;
	}

	while (RET_SUCCESS != snd_request_pcm_buff(g_snd_dev, pcm->samp_num))
	{
		//PRINTF("snd dev not enough PCM buffer.\n");
		osal_task_sleep(10);
	}

	snd_write_pcm_data(g_snd_dev, pcm, (UINT32*)pcm_frm_header);
	if (RET_SUCCESS != snd_data_enough(g_snd_dev))
	{
		snd_write_pcm_data(g_snd_dev, pcm, (UINT32*)pcm_frm_header);
		snd_write_pcm_data(g_snd_dev, pcm, (UINT32*)pcm_frm_header);
	}
	return ;
}

static void pcm_play_demo(void)
{
	struct deca_feature_config deca_config;
	struct snd_feature_config snd_config;
	UINT32 i, j;
	struct pcm_output pcm;
	INT32 *p_pcm_sp;



	g_decv_dev = dev_get_by_id(HLD_DEV_TYPE_DECV, 0);
	g_deca_dev  = dev_get_by_id(HLD_DEV_TYPE_DECA, 0);

	if (RET_SUCCESS != deca_open(g_deca_dev, 0, 0, 0, 0, 0))
	{
		PRINTF("deca_open failed!!\n");
		ASSERT(0);
	}

	if (RET_SUCCESS != snd_open(g_snd_dev))
	{
		PRINTF("snd_open failed!!\n");
		ASSERT(0);
	}

	MEMSET(&pcm, 0, sizeof(struct pcm_output));

	pcm.ch_num = 2;
	pcm.ch_mod = DUAL_CHANNEL;
	pcm.ch_left = pcm_left_ch;
	pcm.ch_right = pcm_right_ch;
	pcm.samp_num = 1152;

	snd_set_spdif_type(g_snd_dev, SND_OUT_SPDIF_PCM);
	snd_set_volume(g_snd_dev, SND_SUB_OUT, 100);
	snd_set_duplicate(g_snd_dev, SND_DUP_NONE);

	/*assumes PCM data is in address __MM_AUDIO_PATTERN_ADDR, 400*4608 samples,
	Preset PCM sample rate is 48000, each sample occupy 1 double word (32 bits)*/

	while (1)
	{
		p_pcm_sp = (INT32 *)__MM_AUDIO_PATTERN_ADDR;
		for (i = 0;i < PCM_FRM_NUM;i++)
		{
			for (j = 0;j < pcm.samp_num;j++)
			{
				/*for dual channel mode, 2 channels should have different samples,
				herel fills the same samples to 2 channels for demo.
				If only have 1 channel PCM, you can only fill 1 channel (left or right), but you should call
				snd_set_duplicate(g_snd_dev, SND_DUP_L); or snd_set_duplicate(g_snd_dev, SND_DUP_R);
				before play.*/
				pcm_left_ch[j] = (*p_pcm_sp) << 5;
				pcm_right_ch[j] = (*p_pcm_sp) << 5;
				p_pcm_sp++;
			}
			libc_demo_pcm_output(&pcm);
		}
	}
}

#endif

#if 0
int ogg_decoder(const char *ogg_file, const char *pcm_file)
{
	OggVorbis_File vf;
	int eof = 0;
	int current_section;
	int tm1, tm2;
	FILE *fin, *fout;

	//open the ogg file
	fin = fopen(ogg_file, "rb");
	if (fin == NULL)
	{
		libc_printf("open the ogg file: %s failed!\n", ogg_file);
		return -1;
	}

	//create the pcm file
#if 0
	fout = fopen(pcm_file, "wb");
	if (fout == NULL)
	{
		libc_printf("open the ogg file: %s failed!\n", pcm_file);
		return -1;
	}
#endif

	if (ov_open(fin, &vf, NULL, 0) < 0)
	{
		libc_printf("Input does not appear to be an Ogg bitstream.\n");
		return -1;
	}

	/* Throw the comments plus a few lines about the bitstream we're
	   decoding */
	{
		char **ptr = ov_comment(&vf, -1)->user_comments;
		vorbis_info *vi = ov_info(&vf, -1);
		while (*ptr)
		{
			libc_printf("%s\n", *ptr);
			++ptr;
		}
		libc_printf("\nBitstream is %d channel, %ldHz\n", vi->channels, vi->rate);
		libc_printf("\nDecoded length: %ld samples\n",
					(long)ov_pcm_total(&vf, -1));
		libc_printf("Encoded by: %s\n\n", ov_comment(&vf, -1)->vendor);
	}

	tm1 = osal_get_tick();


	while (!eof)
	{
		long ret = ov_read(&vf, pcmout, sizeof(pcmout), &current_section);
		if (ret == 0)
		{
			libc_printf("file end!\n");
			/* EOF */
			eof = 1;
		}
		else if (ret < 0)
		{
			libc_printf("error!!!\n");
			/* error in the stream.  Not a problem, just reporting it in
			case we (the app) cares.  In this case, we don't. */
		}
		else
		{
			/* we don't bother dealing with sample rate changes, etc, but
			you'll have to*/
			//fwrite(pcmout, ret, 1, fout);
		}
	}


	/* cleanup */
	ov_clear(&vf);
	tm2 = osal_get_tick();
	libc_printf("decoding time: %dms [%d ~ %d]\n", tm2 - tm1, tm1, tm2);

	//fclose(fout);

	libc_printf("Done.\n");
	return(0);
}

#endif

